package awk.thread.future;

import awk.thread.ThreadPoolUtils;
import lombok.Data;

import java.util.concurrent.*;

public class FutureTest2 {

    static LinkedBlockingDeque<Future<Task>> taskQueue = new LinkedBlockingDeque<>(300);

    static ConcurrentHashMap<Integer, Future<Task>> resultCache = new ConcurrentHashMap<>();
    static ThreadPoolExecutor pool = ThreadPoolUtils.getPool();

    public static void main(String[] args) throws Exception {
        for (int i = 1; i < 8; i++) {
            int second = i;
            //long taskId = Snowflake.currentTimeMillis();
            Task task = new Task(second, second);
            Future<Task> submit = pool.submit(task);
            taskQueue.add(submit);

            resultCache.put(second, submit);
        }

        Task task3 = getTask2(6);
        Task task2 = getTask2(4);
        Task task1 = getTask2(2);
        System.out.println("task1=" + task1 + ",task2=" + task2 + ",task3=" + task3);
    }

    public static Task getTask2(Integer taskId) throws Exception {
        while (!resultCache.isEmpty()) {
            //这里只是出栈入栈操作,非耗时操作,并发时会导致 taskQueue.poll()= null
            Future<Task> futureTask = resultCache.get(taskId);
            if (null == futureTask) {
                System.out.println("taskQueue poll异常");
            }
            if (futureTask.isDone()) {
                Task result = null;
                try {
                    result = futureTask.get();
                    if (null == result) {
                        System.out.println("futureTask 获取结果异常");
                    }
                } catch (Exception e) {
                    System.out.println("QueryExecute execute查询数据异常");
                    throw new Exception("QueryExecute.execute查询数据异常 ");
                }
                if (result.getTaskId().equals(taskId)) {
                    resultCache.remove(taskId);
                    //已经完成的任务调用get()方法获取结果
                    System.out.println("获取到taskId=" + taskId + "的结果");
                    return result;
                }
            }
            System.out.println("。。。。。。。");
        }
        return null;
    }

    public static Task getTask(Integer taskId) throws Exception {
        while (!taskQueue.isEmpty()) {
            //这里只是出栈入栈操作,非耗时操作,并发时会导致 taskQueue.poll()= null
            Future<Task> futureTask = taskQueue.pollFirst();
            if (null == futureTask) {
                System.out.println("taskQueue poll异常");
            }
            if (!futureTask.isDone()) {
                taskQueue.addLast(futureTask);
            } else {
                Task result = null;
                try {
                    result = futureTask.get();
                    if (null == result) {
                        System.out.println("futureTask 获取结果异常");
                    }
                } catch (Exception e) {
                    System.out.println("QueryExecute.execute查询数据异常");
                    throw new Exception("QueryExecute.execute查询数据异常 ");
                }
                if (result.getTaskId().equals(taskId)) {
                    //已经完成的任务调用get()方法获取结果
                    System.out.println("获取到taskId=" + taskId + "的结果");
                    return result;
                } else {
                    //已经get取出的不能再set回去
                    Task finalResult = result;
                    futureTask = new FutureTask<>(() -> finalResult);
                    //并发访问中，尾部可以被错误地修改，并且如果尾部被损坏，则可能永远不会到达head == tail，因此NullPointerException。
                    taskQueue.addLast(futureTask);
                }
            }
        }
        return null;
    }


    @Data
    static class Task implements Callable<Task> {
        private Integer taskId;
        private Integer costTime;
        private String result;

        public Task(Integer taskId, Integer costTime) {
            this.taskId = taskId;
            this.costTime = costTime;
        }

        @Override
        public Task call() {
            try {
                Thread.sleep(costTime * 1000);
                System.out.println(" doing something.....,taskId=" + taskId);
                if (taskId % 3 == 0) {
                    System.out.println("这个任务失败了");
                    throw new Exception("这个任务失败了");
                } else {
                    System.out.println("这个任务成功了" + taskId);
                    this.setResult("这个任务成功了" + taskId);
                    return this;
                }
            } catch (Exception e) {
            }
            return null;
        }
    }
}
